package com.dferreira.repository.data_utils;

import android.text.TextUtils;

import com.dferreira.repository.data_models.RepositoryDependency;
import com.dferreira.repository.data_models.RepositoryPackage;

import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;

import java.util.ArrayList;
import java.util.List;

public class XMLRepositoryParser extends DefaultHandler {
    private Integer repositoryVersion;
    private final List<RepositoryPackage> repositoryPackages;
    private final List<RepositoryDependency> repositoryDependencies;
    private Boolean onADependency;
    private String dependencyValue;

    /**
     * Constructor
     * Starts the variables to the repository parsing
     */
    public XMLRepositoryParser() {
        super();
        this.repositoryPackages = new ArrayList<RepositoryPackage>();
        this.repositoryDependencies = new ArrayList<RepositoryDependency>();
        this.onADependency = false;
    }

    /**
     * Called when tag starts
     *
     * @param uri        The Namespace URI, or the empty string if the element has no Namespace URI or if Namespace processing is not being performed.
     * @param localName  The local name (without prefix), or the empty string if Namespace processing is not being performed.
     * @param qName      The qualified name (with prefix), or the empty string if qualified names are not available.
     * @param attributes The attributes attached to the element. If there are no attributes, it shall be an empty Attributes object.
     */
    @Override
    public void startElement(String uri, String localName, String qName,
                             Attributes attributes) {
        if (localName.equals("repository")) {
            this.repositoryVersion = Integer.valueOf(attributes.getValue("version"));
        } else if (localName.equals("package")) {
            RepositoryPackage repositoryPackage;
            repositoryPackage = new RepositoryPackage();
            repositoryPackage.setName(attributes.getValue("name"));
            repositoryPackage
                    .setDescription(attributes.getValue("description"));
            repositoryPackage.setVersion(Integer.valueOf(attributes
                    .getValue("version")));
            repositoryPackage.setAuthor(attributes.getValue("author"));
            repositoryPackage.setCompressedSize(Long.valueOf(attributes
                    .getValue("compressedSize")));
            repositoryPackage.setUncompressedSize(Long.valueOf(attributes
                    .getValue("uncompressedSize")));
            repositoryPackage.setUrl(attributes.getValue("url"));
            repositoryPackages.add(repositoryPackage);
        } else if (localName.equals("dependency")) {
            onADependency = true;
            dependencyValue = "";
        }
    }

    /**
     * @param ch     The characters.
     * @param start  The start position in the character array.
     * @param length The number of characters to use from the character array.
     */
    public void characters(char ch[], int start, int length) {
        String text = "";
        // loop through the character array
        for (int i = start; i < (start + length); i++) {
            text += ch[i];
        }
        // prepare for the next item
        if (onADependency && text.length() > 0) {
            dependencyValue += text;
        }
    }

    /**
     * Called when tag ends
     *
     * @param uri       The Namespace URI, or the empty string if the element has no Namespace URI or if Namespace processing is not being performed.
     * @param localName The local name (without prefix), or the empty string if Namespace processing is not being performed.
     * @param qName     The qualified name (with prefix), or the empty string if qualified names are not available.
     */
    @Override
    public void endElement(String uri, String localName, String qName) {
        RepositoryDependency repositoryDependency;

        if (localName.equals("dependency")) {
            onADependency = false;
            repositoryDependency = new RepositoryDependency();
            repositoryDependency.setForPackage(repositoryPackages.get(
                    repositoryPackages.size() - 1));
            repositoryDependency.setFromPackage(getRepositoryPackagesByName(dependencyValue));
            repositoryDependencies.add(repositoryDependency);
        }
    }

    /**
     * @return
     */
    private RepositoryPackage getRepositoryPackagesByName(String pkgName) {
        if (TextUtils.isEmpty(pkgName)) {
            return null;
        }
        for (int i = 0; i < repositoryPackages.size(); i++) {
            RepositoryPackage repositoryPackage = repositoryPackages.get(i);
            if (pkgName.equals(repositoryPackage.getName())) {
                return repositoryPackage;
            }
        }
        return null;
    }

    /**
     * @return version from the repository
     */
    public Integer getRepositoryVersion() {
        return repositoryVersion;
    }

    /**
     * @return packages that are in the repository
     */
    public List<RepositoryPackage> getRepositoryPackages() {
        return repositoryPackages;
    }

    /**
     * @return dependencies that exists between packages
     */
    public List<RepositoryDependency> getRepositoryDependencies() {
        return repositoryDependencies;
    }
}
